<!DOCTYPE html>
<html>
<head>
	<title>08-interpreter</title>
	<script type="text/javascript" src="js/mummy.js" charset="utf-8"></script>

</head>

<body>

<script type="text/javascript" charset="utf-8">

Interface(
	function IVariable(){
		this.getName =function(){};
		this.setName =function(){};
		this.getValue=function(){};
		this.setValue=function(){};
	}
); // End of IVariable

Class({
	$implements:[IVariable],
	$define:function  Variable(){
		this._name;
		this._value;
		
		this.getName =function(){return this._name;};
		this.setName =function(value){this._name=value;};
		this.getValue=function(){return this._value;};
		this.setValue=function(value){this._value=value};		
		
		this.Variable = function(name,value){
			this._name=name;
			this._value=value;
		}

	}
}); // End of Variable

Class({
	$define:function  Context(){
		this.varList = new Object();
		
		this.assign = function(variable){
			if($(variable).Implements(IVariable)){
				this.varList[variable.getName()]=variable;
			}else{throw 'Bad type, this does not implements IVariable';}
		}
		
		this.getVariable = function(var_name){return this.varList[var_name];}
		this.getValueOf = function(var_name){return this.varList[var_name].getValue();}

		this.Context = function(){}
	}

}); // End of Context

Interface(
	function IExpression(){
		this.evaluate=function(){};
	}
); // End of IExpression

Class({
	$implements:[IExpression],
	$define:function  TerminalExpression(){
		this.variableName;
		this.TerminalExpression = function(var_name){
			this.variableName = var_name;
		}
		this.evaluate = function(context){
			if($(context).Is(Context)){
				//return context.getVariable(this.variableName);
				return context.getValueOf(this.variableName);
			}else{throw 'Bad type, this is not a Context';}
		}
	}

}); // End of TerminalExpression	

Class($abstract,{
	$implements:[IExpression],
	$define:function NonTerminalExpression(){
		this.leftNode;
		this.rightNode;

		this.setLeftNode = function(node){
			if($(node).Implements(IExpression)){
				this.leftNode=node;
			}else{throw 'Bad type, this does not implements IExpression';}
		}
		
		this.setRightNode = function(node){
			if($(node).Implements(IExpression)){
				this.rightNode=node;
			}else{throw 'Bad type, this does not implements IExpression';}
		}

		this.getLeftNode = function(){
			return this.leftNode;
		}

		this.getRightNode = function(){
			return this.rightNode;
		}

		this.NonTerminalExpression = function(left,right){
			this.setLeftNode(left);
			this.setRightNode(right);
		}
		
		this.evaluate = function(){}
	}

});// End of NonTerminalExpression

Class({
	$extends:NonTerminalExpression,
	$define:function AddExpression(){
		
		this.evaluate = function(context){
			if($(context).Is(Context)){
				return this.getLeftNode().evaluate(context)+this.getRightNode().evaluate(context);
			}else{throw 'Bad type, this is not a Context';}
		}
		
		this.AddExpression = function(left,right){
			this.NonTerminalExpression(left,right);
		}
	}
}); // End of AddExpression

Class({
	$extends:NonTerminalExpression,
	$define:function SubtractExpression(){

		this.evaluate = function(context){
			if($(context).Is(Context)){
				return this.getLeftNode().evaluate(context)-this.getRightNode().evaluate(context);
			}else{throw 'Bad type, this is not a Context';}
		}

		this.SubtractExpression = function(left,right){
			this.NonTerminalExpression(left,right);
		}
	}

}); // End of SubtractExpression

Class({
	$extends:NonTerminalExpression,
	$define:function MultiplyExpression(){

		this.evaluate = function(context){
			if($(context).Is(Context)){
				return this.getLeftNode().evaluate(context)*this.getRightNode().evaluate(context);
			}else{throw 'Bad type, this is not a Context';}
		}
		
		this.MultiplyExpression = function(left,right){
			this.NonTerminalExpression(left,right);
		}

	}

}); // End of MultiplyExpression

Class({
	$extends:NonTerminalExpression,
	$define:function DivideExpression(){

		this.evaluate = function(context){
			if($(context).Is(Context)){
				return this.getLeftNode().evaluate(context)/this.getRightNode().evaluate(context);
			}else{throw 'Bad type, this is not a Context';}
		}

		this.DivideExpression = function(left,right){
			this.NonTerminalExpression(left,right);
		}

	}

}); // End of DivideExpression


Class({
	$define:function Calculator(){
		//this.signature = arguments.callee.toString();
		this.context;
				
		this.getNonTerminalExpression=function(operation,left,right){
			
			switch(operation){
				case "+":
					return $(AddExpression).getNew(left,right);
				break;
				case "-":
					return $(SubtractExpression).getNew(left,right);
				break;
				case "*":
					return $(MultiplyExpression).getNew(left,right);
				break;	
				case "/":
					return $(DivideExpression).getNew(left,right);
				break;								
				default:
					return null;
				break;
			}
		}
		
		
		this.setValueVariable = function(var_name,var_value){
			this.context.assign($(Variable).getNew(var_name,var_value));
		}
		
		this.getValueVariable = function(var_name){
			return this.context.getValueOf(var_name);
		}
		
		this.add=function(var_name_1,var_name_2){
			return this.getNonTerminalExpression("+",
				$(TerminalExpression).getNew(var_name_1),
				$(TerminalExpression).getNew(var_name_2)
			).evaluate(this.context)
		}
		
		this.sub=function(var_name_1,var_name_2){
			return this.getNonTerminalExpression("-",
				$(TerminalExpression).getNew(var_name_1),
				$(TerminalExpression).getNew(var_name_2)
			).evaluate(this.context)
		}
		
		this.mult=function(var_name_1,var_name_2){
			return this.getNonTerminalExpression("*",
				$(TerminalExpression).getNew(var_name_1),
				$(TerminalExpression).getNew(var_name_2)
			).evaluate(this.context)
		}		
		
		this.div=function(var_name_1,var_name_2){
			return this.getNonTerminalExpression("/",
				$(TerminalExpression).getNew(var_name_1),
				$(TerminalExpression).getNew(var_name_2)
			).evaluate(this.context)
		}			
		
		this.Calculator = function(){
			this.context = $(Context).getNew();
			//console.log(arguments.callee.toString());
			//console.log(this.signature);
		}

	}

}); // End of Calculator


var calc = $(Calculator).getNew();

calc.setValueVariable("A",125);
calc.setValueVariable("B",10);
calc.setValueVariable("C",48);
calc.setValueVariable("G",100);

calc.setValueVariable("D",calc.add("A","B"));
calc.setValueVariable("E",calc.sub("D","C"));
calc.setValueVariable("F",calc.mult("D","E"));
calc.setValueVariable("G",calc.div("F","G"));

console.log(calc.getValueVariable("D"));
console.log(calc.getValueVariable("E"));
console.log(calc.getValueVariable("F"));
console.log(calc.getValueVariable("G"));

</script>


</body>
</html>
